
//////////////////////////////////////////////////////////////////////
//
//	Crytek CryENGINE Source code
//	
//	File:Log.h
//
//	History:
//	-Feb 2,2001:Created by Marco Corbetta
//
//////////////////////////////////////////////////////////////////////

#ifndef LOG_H
#define LOG_H

#if _MSC_VER > 1000
# pragma once
#endif

#include <ILog.h>
#include <CryThread.h>
#include <MultiThread.h>
#include <MultiThread_Containers.h>

//////////////////////////////////////////////////////////////////////

#if defined(WIN32) || defined(WIN64) || defined(LINUX)
#define MAX_TEMP_LENGTH_SIZE	2048
#else
#define MAX_TEMP_LENGTH_SIZE	512
// reduce max warning length for consoles (e.g. to prevent overflows on PS3 where thread stack are rather small)
#endif

#define MAX_FILENAME_SIZE			256

#if defined( DEDICATED_SERVER )
#define KEEP_LOG_FILE_OPEN 1
#else
#define KEEP_LOG_FILE_OPEN 0
#endif

//////////////////////////////////////////////////////////////////////
class CLog :public ILog
{
	enum EFilterLogType
	{
		eLogFilterConsole	= BIT(0),
		eLogFilterFile		= BIT(1),
	};

public:
	typedef std::list<ILogCallback*> Callbacks;	
	typedef CryFixedStringT<MAX_TEMP_LENGTH_SIZE> LogStringType;

	// constructor
	CLog( ISystem *pSystem );
	// destructor
	~CLog();


	// interface ILog, IMiniLog -------------------------------------------------

	virtual void Release() { delete this; };
	VIRTUAL bool SetFileName(const char *filename);		
	VIRTUAL const char*	GetFileName();
	VIRTUAL const char* GetBackupFileName();
#if !defined(EXCLUDE_NORMAL_LOG)
	VIRTUAL void Log(const char *command,...) PRINTF_PARAMS(2, 3);
	VIRTUAL void LogAlways(const char *command,...) PRINTF_PARAMS(2, 3);
	VIRTUAL void LogWarning(const char *command,...) PRINTF_PARAMS(2, 3);
	VIRTUAL void LogError(const char *command,...) PRINTF_PARAMS(2, 3);
	VIRTUAL void LogPlus(const char *command,...) PRINTF_PARAMS(2, 3);
	VIRTUAL void LogToFile	(const char *command,...) PRINTF_PARAMS(2, 3);
  VIRTUAL void LogToFilePlus(const char *command,...) PRINTF_PARAMS(2, 3);
	VIRTUAL void LogToConsole(const char *command,...) PRINTF_PARAMS(2, 3);
	VIRTUAL void LogToConsolePlus(const char *command,...) PRINTF_PARAMS(2, 3);
#else
	VIRTUAL void Log(const char *command,...) PRINTF_PARAMS(2, 3) {};
	VIRTUAL void LogAlways(const char *command,...) PRINTF_PARAMS(2, 3) {};
	VIRTUAL void LogWarning(const char *command,...) PRINTF_PARAMS(2, 3) {};
	VIRTUAL void LogError(const char *command,...) PRINTF_PARAMS(2, 3) {};
	VIRTUAL void LogPlus(const char *command,...) PRINTF_PARAMS(2, 3) {};
	VIRTUAL void LogToFile	(const char *command,...) PRINTF_PARAMS(2, 3) {};
	VIRTUAL void LogToFilePlus(const char *command,...) PRINTF_PARAMS(2, 3) {};
	VIRTUAL void LogToConsole(const char *command,...) PRINTF_PARAMS(2, 3) {};
	VIRTUAL void LogToConsolePlus(const char *command,...) PRINTF_PARAMS(2, 3) {};
#endif // !defined(EXCLUDE_NORMAL_LOG)
	VIRTUAL void UpdateLoadingScreen(const char *command,...) PRINTF_PARAMS(2, 3);
	VIRTUAL void SetVerbosity( int verbosity );
	VIRTUAL int	 GetVerbosityLevel();
	VIRTUAL void RegisterConsoleVariables();
	VIRTUAL void UnregisterConsoleVariables();
	VIRTUAL void AddCallback( ILogCallback *pCallback );
	VIRTUAL void RemoveCallback( ILogCallback *pCallback );
	virtual void LogV( const ELogType ineType, const char* szFormat, va_list args );
	VIRTUAL void Update();
	VIRTUAL const char* GetModuleFilter();
	VIRTUAL void FlushAndClose();

private: // -------------------------------------------------------------------

#if !defined(EXCLUDE_NORMAL_LOG)
	void LogStringToFile( const char* szString,bool bAdd,bool bError=false, bool bFromUpdate=false );
	void LogStringToConsole( const char* szString,bool bAdd=false, bool bFromUpdate=false );
#else
	void LogStringToFile( const char* szString,bool bAdd,bool bError=false, bool bFromUpdate=false ) {};
	void LogStringToConsole( const char* szString,bool bAdd=false, bool bFromUpdate=false ) {};
#endif // !defined(EXCLUDE_NORMAL_LOG)

	FILE* OpenLogFile( const char *filename,const char *mode );
	void CloseLogFile( bool force=false );

	// will format the message into m_szTemp
	void FormatMessage(const char *szCommand, ... ) PRINTF_PARAMS(2, 3);

#ifndef _RELEASE
	void Indent(CLogIndenter * indenter);
	void Unindent(CLogIndenter * indenter);
	void BuildIndentString();
	VIRTUAL void PushAssetScopeName( const char *sAssetType,const char *sName );
	VIRTUAL void PopAssetScopeName();
	VIRTUAL const char* GetAssetScopeString();
#endif

	ISystem	*				m_pSystem;														//
	float						m_fLastLoadingUpdateTime;							// for non-frequent streamingEngine update
	//char						m_szTemp[MAX_TEMP_LENGTH_SIZE];				//
	char						m_szFilename[MAX_FILENAME_SIZE];			// can be with path
	mutable char		m_sBackupFilename[MAX_FILENAME_SIZE];	// can be with path
	FILE *					m_pLogFile;
	CryStackStringT<char, 32> m_LogMode;														//mode m_pLogFile has been opened with
	FILE *					m_pErrFile;
	int							m_nErrCount;

#ifndef _RELEASE
	uint8                   m_indentation;
	LogStringType           m_indentWithString;
	class CLogIndenter    * m_topIndenter;

	struct SAssetScopeInfo
	{
		string sType;
		string sName;
	};

	std::vector<SAssetScopeInfo> m_assetScopeQueue;
	CryCriticalSection m_assetScopeQueueLock;
	string m_assetScopeString;
#endif

	ICVar *					m_pLogIncludeTime;										//
	
	IConsole *			m_pConsole;														//

	CryCriticalSection m_logCriticalSection;

	struct SLogHistoryItem
	{
		char str[MAX_WARNING_LENGTH];
		const char *ptr;
		ELogType type;
		float time;
	};
	SLogHistoryItem m_history[16];
	int m_iLastHistoryItem;

#if KEEP_LOG_FILE_OPEN
	bool            m_bFirstLine;
#if !( defined( PS3 ) || defined( XENON ) )
	char            m_logBuffer[ 0x200000 ];
#endif
#endif

public: // -------------------------------------------------------------------

	void GetMemoryUsage(ICrySizer *pSizer) const
	{
		pSizer->AddObject(this, sizeof(*this));
		pSizer->AddObject(m_pLogVerbosity);
		pSizer->AddObject(m_pLogWriteToFile);
		pSizer->AddObject(m_pLogWriteToFileVerbosity);
		pSizer->AddObject(m_pLogVerbosityOverridesWriteToFile);
		pSizer->AddObject(m_pLogSpamDelay);
		pSizer->AddObject(m_threadSafeMsgQueue);
	}
	// checks the verbosity of the message and returns NULL if the message must NOT be
	// logged, or the pointer to the part of the message that should be logged
	const char* CheckAgainstVerbosity(const char * pText, bool &logtofile, bool &logtoconsole, const uint8 DefaultVerbosity=2 );

	// checks if the log message is filtered
	bool CheckAgainstStringFilter(const char * pText) const;

	// create backup of log file, useful behavior - only on development platform
	void CreateBackupFile() const;

	ICVar *					m_pLogVerbosity;											//
	ICVar *					m_pLogWriteToFile;										//
	ICVar *					m_pLogWriteToFileVerbosity;						//
	ICVar *					m_pLogVerbosityOverridesWriteToFile;	//
	ICVar *					m_pLogSpamDelay;                      //
	ICVar *					m_pLogModule;													// Module filter for log
	ICVar *					m_pLogFilters;												// general string filters for log
	ICVar *					m_pLogUseFilters;											//
	Callbacks				m_callbacks;													//

	uint32 m_nMainThreadId;

	struct SLogMsg
	{
		char msg[512];
		bool bError;
		bool bAdd;
		bool bConsole;
		void GetMemoryUsage(ICrySizer *pSizer) const{}
	};
	CryMT::queue<SLogMsg> m_threadSafeMsgQueue;
};


#endif

